/*-------------------------------------------------------------------------
 *
 * pg_attrdef.c
 *	  支持操作 pg_attrdef 关系的例程
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/catalog/pg_attrdef.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "access/genam.h"
#include "access/relation.h"
#include "access/table.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_attrdef.h"
#include "executor/executor.h"
#include "optimizer/optimizer.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/rel.h"
#include "utils/syscache.h"


/*  
 * 为关系rel的列attnum存储默认表达式。  
 *  
 * 返回新pg_attrdef元组的OID。  
 *  
 * 如果我们为新属性存储默认值，则add_column_mode必须为true；  
 * 如果它是为已存在属性存储，则为false。原因是，缺失值必须在设置后绝不能被更新，  
 * 这只能在向表中添加列时发生。否则我们实际上将改变现有的元组。  
 */  
Oid StoreAttrDefault(Relation fc_rel, AttrNumber fc_attnum,
				 Node *fc_expr, bool fc_is_internal, bool add_column_mode)
{
	char	   *fc_adbin;
	Relation	fc_adrel;
	HeapTuple	fc_tuple;
	Datum		fc_values[4];
	static bool fc_nulls[4] = {false, false, false, false};
	Relation	fc_attrrel;
	HeapTuple	fc_atttup;
	Form_pg_attribute fc_attStruct;
	char		fc_attgenerated;
	Oid			fc_attrdefOid;
	ObjectAddress fc_colobject,
				fc_defobject;

	fc_adrel = table_open(AttrDefaultRelationId, RowExclusiveLock);

	/*
	 * 将表达式展平为字符串形式以进行存储。
	 */
	fc_adbin = nodeToString(fc_expr);

	/*  
	 * 创建pg_attrdef条目。  
	 */  
	fc_attrdefOid = GetNewOidWithIndex(fc_adrel, AttrDefaultOidIndexId,
									Anum_pg_attrdef_oid);
	fc_values[Anum_pg_attrdef_oid - 1] = ObjectIdGetDatum(fc_attrdefOid);
	fc_values[Anum_pg_attrdef_adrelid - 1] = RelationGetRelid(fc_rel);
	fc_values[Anum_pg_attrdef_adnum - 1] = fc_attnum;
	fc_values[Anum_pg_attrdef_adbin - 1] = CStringGetTextDatum(fc_adbin);

	fc_tuple = heap_form_tuple(fc_adrel->rd_att, fc_values, fc_nulls);
	CatalogTupleInsert(fc_adrel, fc_tuple);

	fc_defobject.classId = AttrDefaultRelationId;
	fc_defobject.objectId = fc_attrdefOid;
	fc_defobject.objectSubId = 0;

	table_close(fc_adrel, RowExclusiveLock);

	/* 现在可以释放上面分配的一些东西 */  
	pfree(DatumGetPointer(fc_values[Anum_pg_attrdef_adbin - 1]));
	heap_freetuple(fc_tuple);
	pfree(fc_adbin);

	/*  
	 * 更新pg_attribute条目以显示存在默认值。  
	 */  
	fc_attrrel = table_open(AttributeRelationId, RowExclusiveLock);
	fc_atttup = SearchSysCacheCopy2(ATTNUM,
								 ObjectIdGetDatum(RelationGetRelid(fc_rel)),
								 Int16GetDatum(fc_attnum));
	if (!HeapTupleIsValid(fc_atttup))
		elog(ERROR, "cache lookup failed for attribute %d of relation %u",
			 fc_attnum, RelationGetRelid(fc_rel));
	fc_attStruct = (Form_pg_attribute) GETSTRUCT(fc_atttup);
	fc_attgenerated = fc_attStruct->attgenerated;
	if (!fc_attStruct->atthasdef)
	{
		Form_pg_attribute fc_defAttStruct;

		ExprState  *fc_exprState;
		Expr	   *fc_expr2 = (Expr *) fc_expr;
		EState	   *fc_estate = NULL;
		ExprContext *fc_econtext;
		Datum		fc_valuesAtt[Natts_pg_attribute];
		bool		fc_nullsAtt[Natts_pg_attribute];
		bool		fc_replacesAtt[Natts_pg_attribute];
		Datum		fc_missingval = (Datum) 0;
		bool		fc_missingIsNull = true;

		MemSet(fc_valuesAtt, 0, sizeof(fc_valuesAtt));
		MemSet(fc_nullsAtt, false, sizeof(fc_nullsAtt));
		MemSet(fc_replacesAtt, false, sizeof(fc_replacesAtt));
		fc_valuesAtt[Anum_pg_attribute_atthasdef - 1] = true;
		fc_replacesAtt[Anum_pg_attribute_atthasdef - 1] = true;

		if (fc_rel->rd_rel->relkind == RELKIND_RELATION && add_column_mode &&
			!fc_attgenerated)
		{
			fc_expr2 = expression_planner(fc_expr2);
			fc_estate = CreateExecutorState();
			fc_exprState = ExecPrepareExpr(fc_expr2, fc_estate);
			fc_econtext = GetPerTupleExprContext(fc_estate);

			fc_missingval = ExecEvalExpr(fc_exprState, fc_econtext,
									  &fc_missingIsNull);

			FreeExecutorState(fc_estate);

			fc_defAttStruct = TupleDescAttr(fc_rel->rd_att, fc_attnum - 1);

			if (fc_missingIsNull)
			{
				/* 如果默认计算结果为NULL，仅存储一个NULL数组 */  
				fc_missingval = (Datum) 0;
			}
			else
			{
				/* 否则创建一个值的一元素数组 */  
				fc_missingval = PointerGetDatum(construct_array(&fc_missingval,
															 1,
															 fc_defAttStruct->atttypid,
															 fc_defAttStruct->attlen,
															 fc_defAttStruct->attbyval,
															 fc_defAttStruct->attalign));
			}

			fc_valuesAtt[Anum_pg_attribute_atthasmissing - 1] = !fc_missingIsNull;
			fc_replacesAtt[Anum_pg_attribute_atthasmissing - 1] = true;
			fc_valuesAtt[Anum_pg_attribute_attmissingval - 1] = fc_missingval;
			fc_replacesAtt[Anum_pg_attribute_attmissingval - 1] = true;
			fc_nullsAtt[Anum_pg_attribute_attmissingval - 1] = fc_missingIsNull;
		}
		fc_atttup = heap_modify_tuple(fc_atttup, RelationGetDescr(fc_attrrel),
								   fc_valuesAtt, fc_nullsAtt, fc_replacesAtt);

		CatalogTupleUpdate(fc_attrrel, &fc_atttup->t_self, fc_atttup);

		if (!fc_missingIsNull)
			pfree(DatumGetPointer(fc_missingval));
	}
	table_close(fc_attrrel, RowExclusiveLock);
	heap_freetuple(fc_atttup);

	/*  
	 * 创建依赖关系，以便在删除列（或整个表）时pg_attrdef条目消失。  
	 * 在生成列的情况下，设置其为内部依赖，防止默认表达式被单独删除。  
	 */  
	fc_colobject.classId = RelationRelationId;
	fc_colobject.objectId = RelationGetRelid(fc_rel);
	fc_colobject.objectSubId = fc_attnum;

	recordDependencyOn(&fc_defobject, &fc_colobject,
					   fc_attgenerated ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);

	/*  
	 * 记录对表达式中使用的对象的依赖关系。  
	 */  
	recordDependencyOnSingleRelExpr(&fc_defobject, fc_expr, RelationGetRelid(fc_rel),
									DEPENDENCY_NORMAL,
									DEPENDENCY_NORMAL, false);

	/*  
	 * 属性默认值的创建后钩子。  
	 *  
	 * XXX. ALTER TABLE ALTER COLUMN SET/DROP DEFAULT是通过  
	 * 删除/创建属性的默认条目实现的，因此调用者应检查  
	 * 该条目的旧版本的存在情况，如果它需要区分的话。  
	 */  
	InvokeObjectPostCreateHookArg(AttrDefaultRelationId,
								  RelationGetRelid(fc_rel), fc_attnum, fc_is_internal);

	return fc_attrdefOid;
}


/*  
 *		RemoveAttrDefault  
 *  
 * 如果指定的关系/属性具有默认值，则将其删除。  
 * （如果没有默认值，如果complain为true则引发错误，否则静默返回。）  
 */  
void RemoveAttrDefault(Oid fc_relid, AttrNumber fc_attnum,
				  DropBehavior fc_behavior, bool fc_complain, bool fc_internal)
{
	Relation	fc_attrdef_rel;
	ScanKeyData fc_scankeys[2];
	SysScanDesc fc_scan;
	HeapTuple	fc_tuple;
	bool		fc_found = false;

	fc_attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);

	ScanKeyInit(&fc_scankeys[0],
				Anum_pg_attrdef_adrelid,
				BTEqualStrategyNumber, F_OIDEQ,
				ObjectIdGetDatum(fc_relid));
	ScanKeyInit(&fc_scankeys[1],
				Anum_pg_attrdef_adnum,
				BTEqualStrategyNumber, F_INT2EQ,
				Int16GetDatum(fc_attnum));

	fc_scan = systable_beginscan(fc_attrdef_rel, AttrDefaultIndexId, true,
							  NULL, 2, fc_scankeys);

	/* 最多应该只有一个匹配的元组，但我们还是循环一次 */  
	while (HeapTupleIsValid(fc_tuple = systable_getnext(fc_scan)))
	{
		ObjectAddress fc_object;
		Form_pg_attrdef fc_attrtuple = (Form_pg_attrdef) GETSTRUCT(fc_tuple);

		fc_object.classId = AttrDefaultRelationId;
		fc_object.objectId = fc_attrtuple->oid;
		fc_object.objectSubId = 0;

		performDeletion(&fc_object, fc_behavior,
						fc_internal ? PERFORM_DELETION_INTERNAL : 0);

		fc_found = true;
	}

	systable_endscan(fc_scan);
	table_close(fc_attrdef_rel, RowExclusiveLock);

	if (fc_complain && !fc_found)
		elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",
			 fc_relid, fc_attnum);
}

/*  
 *		RemoveAttrDefaultById  
 *  
 * 删除由OID指定的pg_attrdef条目。这是属性默认值删除的核心。  
 * 注意应通过performDeletion调用，而不是直接调用。  
 */  
void RemoveAttrDefaultById(Oid fc_attrdefId)
{
	Relation	fc_attrdef_rel;
	Relation	fc_attr_rel;
	Relation	fc_myrel;
	ScanKeyData fc_scankeys[1];
	SysScanDesc fc_scan;
	HeapTuple	fc_tuple;
	Oid			fc_myrelid;
	AttrNumber	fc_myattnum;

	/* 在pg_attrdef关系上获取适当的锁 */  
	fc_attrdef_rel = table_open(AttrDefaultRelationId, RowExclusiveLock);

	/* 查找pg_attrdef元组 */  
	ScanKeyInit(&fc_scankeys[0],
				Anum_pg_attrdef_oid,
				BTEqualStrategyNumber, F_OIDEQ,
				ObjectIdGetDatum(fc_attrdefId));

	fc_scan = systable_beginscan(fc_attrdef_rel, AttrDefaultOidIndexId, true,
							  NULL, 1, fc_scankeys);

	fc_tuple = systable_getnext(fc_scan);
	if (!HeapTupleIsValid(fc_tuple))
		elog(ERROR, "could not find tuple for attrdef %u", fc_attrdefId);

	fc_myrelid = ((Form_pg_attrdef) GETSTRUCT(fc_tuple))->adrelid;
	fc_myattnum = ((Form_pg_attrdef) GETSTRUCT(fc_tuple))->adnum;

	/* 获取拥有属性的关系上的排他锁 */  
	fc_myrel = relation_open(fc_myrelid, AccessExclusiveLock);

	/* 现在我们可以删除 pg_attrdef 行 */
	CatalogTupleDelete(fc_attrdef_rel, &fc_tuple->t_self);

	systable_endscan(fc_scan);
	table_close(fc_attrdef_rel, RowExclusiveLock);

	 /* 修复 pg_attribute 行 */
	fc_attr_rel = table_open(AttributeRelationId, RowExclusiveLock);

	fc_tuple = SearchSysCacheCopy2(ATTNUM,
								ObjectIdGetDatum(fc_myrelid),
								Int16GetDatum(fc_myattnum));
	if (!HeapTupleIsValid(fc_tuple))	/* 不应该发生 */
		elog(ERROR, "cache lookup failed for attribute %d of relation %u",
			 fc_myattnum, fc_myrelid);

	((Form_pg_attribute) GETSTRUCT(fc_tuple))->atthasdef = false;

	CatalogTupleUpdate(fc_attr_rel, &fc_tuple->t_self, fc_tuple);

	 /*
	 * 我们对 pg_attribute 行的更新将强制重新构建 relcache，因此
	 * 这里没有其他事情要做。
	 */
	table_close(fc_attr_rel, RowExclusiveLock);

	 /* 在事务结束之前保持对属性关系的锁定 */
	relation_close(fc_myrel, NoLock);
}


 /*
 * 获取由关系 OID 和列编号标识的列的默认表达式的 pg_attrdef OID。
 *
 * 如果没有这样的 pg_attrdef 条目，则返回 InvalidOid。
 */
Oid GetAttrDefaultOid(Oid fc_relid, AttrNumber fc_attnum)
{
	Oid			fc_result = InvalidOid;
	Relation	fc_attrdef;
	ScanKeyData fc_keys[2];
	SysScanDesc fc_scan;
	HeapTuple	fc_tup;

	fc_attrdef = table_open(AttrDefaultRelationId, AccessShareLock);
	ScanKeyInit(&fc_keys[0],
				Anum_pg_attrdef_adrelid,
				BTEqualStrategyNumber,
				F_OIDEQ,
				ObjectIdGetDatum(fc_relid));
	ScanKeyInit(&fc_keys[1],
				Anum_pg_attrdef_adnum,
				BTEqualStrategyNumber,
				F_INT2EQ,
				Int16GetDatum(fc_attnum));
	fc_scan = systable_beginscan(fc_attrdef, AttrDefaultIndexId, true,
							  NULL, 2, fc_keys);

	if (HeapTupleIsValid(fc_tup = systable_getnext(fc_scan)))
	{
		Form_pg_attrdef fc_atdform = (Form_pg_attrdef) GETSTRUCT(fc_tup);

		fc_result = fc_atdform->oid;
	}

	systable_endscan(fc_scan);
	table_close(fc_attrdef, AccessShareLock);

	return fc_result;
}

 /*
 * 给定一个 pg_attrdef OID，返回拥有列的关系 OID 和列编号
 * （为方便起见表示为 ObjectAddress）。
 *
 * 如果没有这样的 pg_attrdef 条目，则返回 InvalidObjectAddress。
 */
ObjectAddress GetAttrDefaultColumnAddress(Oid fc_attrdefoid)
{
	ObjectAddress fc_result = InvalidObjectAddress;
	Relation	fc_attrdef;
	ScanKeyData fc_skey[1];
	SysScanDesc fc_scan;
	HeapTuple	fc_tup;

	fc_attrdef = table_open(AttrDefaultRelationId, AccessShareLock);
	ScanKeyInit(&fc_skey[0],
				Anum_pg_attrdef_oid,
				BTEqualStrategyNumber, F_OIDEQ,
				ObjectIdGetDatum(fc_attrdefoid));
	fc_scan = systable_beginscan(fc_attrdef, AttrDefaultOidIndexId, true,
							  NULL, 1, fc_skey);

	if (HeapTupleIsValid(fc_tup = systable_getnext(fc_scan)))
	{
		Form_pg_attrdef fc_atdform = (Form_pg_attrdef) GETSTRUCT(fc_tup);

		fc_result.classId = RelationRelationId;
		fc_result.objectId = fc_atdform->adrelid;
		fc_result.objectSubId = fc_atdform->adnum;
	}

	systable_endscan(fc_scan);
	table_close(fc_attrdef, AccessShareLock);

	return fc_result;
}
